package com.base.thread.demo_23;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

import javax.management.RuntimeErrorException;

public class MyLock implements Lock {

	private Sync sync = new Sync();
	
	private class Sync extends AbstractQueuedSynchronizer {

		@Override
		protected boolean tryAcquire(int arg) {
			Thread currentThread = Thread.currentThread();
			int state = getState();
			System.out.println(Thread.currentThread().getName() + " " + state);
			if (state == 0) {
				if (compareAndSetState(0, arg)) {
					setExclusiveOwnerThread(currentThread);
					return true;
				}
			}
			else if (getExclusiveOwnerThread() == currentThread) {
				setState(state + 1);
				return true;
			}
//			throw new RuntimeException();
			return false;
		}

		@Override
		protected boolean tryRelease(int arg) {
			Thread currentThread = Thread.currentThread();
			if (currentThread != getExclusiveOwnerThread()) {
				throw new RuntimeException();
			}
			int state = getState() - 1;
			setState(state);
			if (state == 0) {
				setExclusiveOwnerThread(null);
				return true;
			}
			return false;
		}
		
		public Condition newCondition() {
			return new ConditionObject();
		}
		
	}
	
	
	@Override
	public void lock() {
		sync.tryAcquire(1);
	}

	@Override
	public void lockInterruptibly() throws InterruptedException {
		sync.acquireInterruptibly(1);
	}

	@Override
	public boolean tryLock() {
		return sync.tryAcquire(1);
	}

	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return sync.tryAcquireNanos(1, unit.toNanos(time));
	}

	@Override
	public void unlock() {
		sync.release(1);
	}

	@Override
	public Condition newCondition() {
		return sync.newCondition();
	}

}
